package com.xqq.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionDemo {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();  // 队列未满条件
    private final Condition notEmpty = lock.newCondition(); // 队列非空条件
    private final Object[] items = new Object[5];
    private int count, putIndex, takeIndex;

    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            // 队列已满时等待
            while (count == items.length) {
                System.out.println("队列已满，生产者等待");
                notFull.await(); // 关键点1：等待notFull信号
            }

            items[putIndex] = x;
            if (++putIndex == items.length) putIndex = 0;
            count++;
            System.out.println("生产: " + x);

            notEmpty.signal(); // 关键点2：通知消费者
        } finally {
            lock.unlock();
        }
    }

    public Object take() throws InterruptedException {
        lock.lock();
        try {
            // 队列为空时等待
            while (count == 0) {
                System.out.println("队列为空，消费者等待");
                notEmpty.await(); // 关键点3：等待notEmpty信号
            }

            Object x = items[takeIndex];
            if (++takeIndex == items.length) takeIndex = 0;
            count--;
            System.out.println("消费: " + x);

            notFull.signal(); // 关键点4：通知生产者
            return x;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ConditionDemo demo = new ConditionDemo();

        // 生产者线程
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    demo.put(i);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }).start();

        // 消费者线程
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    demo.take();
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }).start();
    }
}